﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GeneticAlgorythm.Algorythm
{
    public class CycleCrossover : Crossover
    {
        private PermutationChromosome _firstParentChromosome;
        private PermutationChromosome _secondParentChromosome;
        private PermutationChromosome _firstChildrenChromosome;
        private PermutationChromosome _secondChildrenChromosome;
        private int _startingPoint;
        private int _chromosomeSize;
        private List<bool> _cyclePositions;
        private bool _startingPointAlreadySet = false;

        public CycleCrossover()
        {
        }
        public CycleCrossover(int startingPoint)
        {
            _startingPoint = startingPoint;
            _startingPointAlreadySet = true;
        }

        public List<Chromosome> execute(Chromosome firstParent, Chromosome secondParent)
        {
            setUps(firstParent, secondParent);

            if(!_startingPointAlreadySet)
            {
                _startingPoint = RandomGenerator.getInstance().generateRandomIntegerFromZeroTo(_chromosomeSize);
            }

            searchForCycle();

            fillChildrenWithApropriateGenes();

            return new List<Chromosome> { _firstChildrenChromosome, _secondChildrenChromosome };
        }
        private void setUps(Chromosome firstParent, Chromosome secondParent)
        {
            _firstParentChromosome = (PermutationChromosome) firstParent;
            _secondParentChromosome = (PermutationChromosome)secondParent;
            _chromosomeSize = _firstParentChromosome.getSize();
            _firstChildrenChromosome = new PermutationChromosome(_chromosomeSize);
            _secondChildrenChromosome = new PermutationChromosome(_chromosomeSize);
        }

        private void searchForCycle()
        {
            _cyclePositions = generateBitVectorWithAllZeros();
            int currentIndex = _startingPoint;


            _cyclePositions[currentIndex] = true;

            int startGene = (int)_firstParentChromosome.getGene(currentIndex);
            int tmpGene = (int)_secondParentChromosome.getGene(currentIndex);

            while (startGene != tmpGene)
            {
                currentIndex = _firstParentChromosome.find(tmpGene);
                if (currentIndex != -1)
                {
                    tmpGene = (int)_secondParentChromosome.getGene(currentIndex);
                    _cyclePositions[currentIndex] = true;
                }
            }
        }

        private List<bool> generateBitVectorWithAllZeros()
        {
            List<bool> bitVector = new List<bool>();

            for (int i = 0; i < _chromosomeSize; i++)
                bitVector.Add(false);

            return bitVector;
        }

        private void fillChildrenWithApropriateGenes()
        {
            for (int i = 0; i < _chromosomeSize; i++)
            {
                if (_cyclePositions[i].Equals(true))
                {
                    _firstChildrenChromosome.setGene(i, _firstParentChromosome.getGene(i));
                    _secondChildrenChromosome.setGene(i, _secondParentChromosome.getGene(i));
                }
                else
                {
                    _firstChildrenChromosome.setGene(i, _secondParentChromosome.getGene(i));
                    _secondChildrenChromosome.setGene(i, _firstParentChromosome.getGene(i));
                }
            }
        }



    }
}
